﻿using System;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using JmShared;
using System.Linq;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Collections.Generic;
using JiveMessenger.Utilities;
using GalaSoft.MvvmLight.Messaging;
using System.ComponentModel;
using GalaSoft.MvvmLight.Command;
using JiveMessenger.User;
using System.Diagnostics;
using System.Reflection;
using Windows.UI.Xaml.Data;
using System.Threading.Tasks;
using Windows.UI.Core;
using JiveMessenger.Log;
using JiveMessenger.Models;

namespace JiveMessenger.ViewModels
{
    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// See http://www.galasoft.ch/mvvm
    /// </para>
    /// </summary>
    public class ViewModelNotifications : ViewModelBaseEx, IViewModelNotifications
    {
        private readonly CoreDispatcher dispatcher;
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
        private IClient _currentClient;

        public RelayCommand AcceptInviteCommand { get; set; }
        public RelayCommand DeclineInviteCommand { get; set; }

        private string _acceptButtonText;
        public string AcceptButtonText
        {
            get { return _acceptButtonText; }
            set
            {
                if (_acceptButtonText != value)
                {
                    Set(() => AcceptButtonText, ref _acceptButtonText, value);
                }
            }
        }

        private string _declineButtonText;
        public string DeclineButtonText
        {
            get { return _declineButtonText; }
            set
            {
                if (_declineButtonText != value)
                {
                    Set(() => DeclineButtonText, ref _declineButtonText, value);
                }
            }
        }


        private ObservableCollection<NotificationBase> _notifications;
        public ObservableCollection<NotificationBase> Notifications
        {
            get
            {
                if (_notifications == null)
                {
                    this.Notifications = new ObservableCollection<NotificationBase>();
                }
                return _notifications;
            }
            set
            {
                if (_notifications != value)
                {
                    if (_notifications != null)
                        _notifications.CollectionChanged -= Notifications_CollectionChanged;
                    Set(() => Notifications, ref _notifications, value);
                  CreateVisualNotifications();
                    if (_notifications != null)
                        _notifications.CollectionChanged += Notifications_CollectionChanged;
                }
            }
        }

        public int NotificationCount
        {
            get
            {
                return this.Notifications != null ? this.Notifications.Count : 0;
            }
        }


        private bool _haveUnreadNotifications;
        public bool HaveUnreadNotifications
        {
            get { return _haveUnreadNotifications; }
            set
            {
                if (_haveUnreadNotifications != value)
                {
                    Set(() => HaveUnreadNotifications, ref _haveUnreadNotifications, value);
                }
            }
        }

        private ObservableCollection<VisualNotification> _groupedNotifications;
        public ObservableCollection<VisualNotification> GroupedNotifications
        {
            get { return _groupedNotifications; }
            set
            {
                if (_groupedNotifications != value)
                {
                    Set(() => GroupedNotifications, ref _groupedNotifications, value);
                }
            }
        }


        /// <summary>
        /// Initializes a new instance of the ViewModelNotifications class.
        /// </summary>
        public ViewModelNotifications(IClient currentClient)
        {
            GroupedNotifications = new ObservableCollection<VisualNotification>();
            _currentClient = currentClient;

            this.dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
            this.AcceptButtonText = "Accept";
            this.DeclineButtonText = "Decline";
            this.AcceptInviteCommand = new RelayCommand(AcceptInviteCommandAction, AcceptCommandCanExecute);
            this.DeclineInviteCommand = new RelayCommand(DeclineInviteCommandAction, DeclineCommandCanExecute);

            Messenger.Default.Register<NotificationMessage<IEnumerable<NotificationBase>>>(this, msg =>
            {
                switch (msg.Notification)
                {
                    case "AddNotificationList":
                        {
                            Notifications.Clear();
                            foreach (var n in msg.Content)
                            {
                                Notifications.Add(n);
                            }
                            break;
                        }
                }
            });
        }
        private async Task OnUiThread(Action action)
        {
            await this.dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action());
        }
        private async Task OnUiThread(Func<Task> action)
        {
            await this.dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => await action());
        }

        private void CreateVisualNotifications()
        {

                
            this.GroupedNotifications.Clear();
           // var groupedNotifications = new ObservableCollection<VisualNotification>();
            var splittedGroups = this.Notifications.ToLookup(x => x.NotificationType);

            foreach (var group in splittedGroups)
            {
                this.GroupedNotifications.Add(new VisualNotification(group.Key, new ObservableCollection<NotificationBase>(group)));
            }
          
        }

        private bool AcceptCommandCanExecute()
        {
            if (this.Notifications == null || this.NotificationCount == 0 || !this.Notifications.Any(x => x.IsSelected))
                return false;

            else if (!this.Notifications.Where(x => x.IsSelected).Any(x => x.NotificationType != NotificationType.FriendInvite && x.NotificationType != NotificationType.GroupInvite))
            {
                this.AcceptButtonText = "Accept";
                this.DeclineButtonText = "Decline";
                return true;
            }
            else if (this.Notifications.Where(x => x.IsSelected).Any(x => x.NotificationType == NotificationType.ServerMessage))
            {
                this.AcceptButtonText = "Dismiss";
                this.DeclineButtonText = "Decline";
                return true;
            }
            this.AcceptButtonText = "Accept";
            this.AcceptButtonText = "Decline";
            return false;
        }
        private bool DeclineCommandCanExecute()
        {
            if (this.Notifications == null || this.NotificationCount == 0)
                return false;

            if (!this.Notifications.Any(x => x.IsSelected))
                return false;
            else if (this.Notifications.Where(x => x.IsSelected).Any(x => x.NotificationType == NotificationType.FriendInvite
                || x.NotificationType == NotificationType.GroupInvite))
                return true;
            else if (this.Notifications.Where(x => x.IsSelected).Any(x => x.NotificationType == NotificationType.ServerMessage))
                return false;

            return false;
        }
        private async void DeclineInviteCommandAction()
        {
            var selectedNotifications = new List<NotificationBase>(this.Notifications.Where(x => x.IsSelected));
            foreach (NotificationBase notification in selectedNotifications)
            {
                IClient currentClient = _currentClient;
                switch (notification.NotificationType)
                {
                    case NotificationType.FriendInvite:
                       await currentClient.Connection.SendMessage(new ChatMessage(currentClient.CurrentUserInfo.ID, currentClient.CurrentUserInfo.UserName, MessageType.DeclineFriendRequest) { RecipientID = ((FriendInviteNotification)notification).SenderUsername });
                        break;
                    case NotificationType.GroupInvite:
                        await currentClient.Connection.SendMessage(new ChatMessage(currentClient.CurrentUserInfo.ID, currentClient.CurrentUserInfo.UserName, MessageType.DeclineGroupInvite) { RecipientID = ((GroupInviteNotification)notification).Group.ID });
                        break;
                    default:
                    case NotificationType.ServerMessage:
                        await currentClient.Connection.SendMessage(new ChatMessage(currentClient.CurrentUserInfo.ID, currentClient.CurrentUserInfo.UserName, MessageType.DeclineGroupInvite) { RecipientID = ((GroupInviteNotification)notification).Group.ID });
                        break;
                }

                this.Notifications.Remove(notification);

            }
        }
        private async void AcceptInviteCommandAction()
        {
            var selectedNotifications = new List<NotificationBase>(this.Notifications.Where(x => x.IsSelected));
            foreach (NotificationBase notification in selectedNotifications)
            {
                IClient currentClient = _currentClient;
                switch (notification.NotificationType)
                {
                    case NotificationType.FriendInvite:
                       await currentClient.Connection.SendMessage(new ChatMessage(currentClient.CurrentUserInfo.ID, currentClient.CurrentUserInfo.UserName, MessageType.AcceptFriendRequest) { RecipientID = ((FriendInviteNotification)notification).SenderUsername });
                        break;
                    case NotificationType.GroupInvite:
                        await currentClient.Connection.SendMessage(new ChatMessage(currentClient.CurrentUserInfo.ID, currentClient.CurrentUserInfo.UserName, MessageType.AcceptGroupInvite) { RecipientID = ((GroupInviteNotification)notification).Group.ID });
                        break;
                    case NotificationType.ServerMessage:
                        await currentClient.Connection.SendMessage(new ChatMessage(currentClient.CurrentUserInfo.ID, currentClient.CurrentUserInfo.UserName, MessageType.DismissServerMessageNotification) { RecipientID = ((ServerMessageNotification)notification).ID });
                        break;
                    case NotificationType.Other:

                        break;
                }

                this.Notifications.Remove(notification);
            }
        }

        void Notifications_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            this.HaveUnreadNotifications = ((ObservableCollection<NotificationBase>)sender).Any(x => !x.IsRead);
             CreateVisualNotifications();
            RaisePropertyChanged("Notifications");
            RaisePropertyChanged("NotificationCount");
        }

       async public override void Cleanup()
        {
            await OnUiThread(() => this.Notifications.Clear());
        }
    }
}